class Parser
  require 'rexml/document'
#De database wordt aangeleverd in een xml bestand en heeft de volgende vorm:
#  <?xml version="1.0" encoding="ISO-8859-15"?>
#  <database>
#  <categories>
#    <category name='Detective'>
#      <category name = 'Engelse detective'> #geneste categorie
#      </category>
#    </category>
#    <category name='Science Fiction'>
#    </category>
#  </categories>
#  <attributes>
#    <attribute name='Titel' searchable = 'true' filterable = 'true'/>
#    <attribute name='Auteur' searchable = 'true' filterable = 'true' />
#    <attribute name='ISBN10'  searchable = 'true'  filterable = 'false' />
#    <attribute name='ISBN13' searchable = 'true'  filterable = 'false' />
#    <attribute name='paginas'  searchable = 'false' filterable = 'false' />
#  </attributes>
#  <products>
#    <product name="Product1" price="10.0" stock="3" description="" image_src="">
#      <product_attribute value="Auteur1" name='Auteur' />
#      <product_attribute value="Auteur2" name='Auteur' />
#      <product_attribute value="Titel1" name='Titel' />
#      <product_category name="Detective" />
#      <product_category name="Science Fiction" />
#    </product>
#  </products>
#</database>
  
  def self.upload_database(file)
    data =  file.read
    parser = Parser.new
    parser.parse_xml_file(data)
    file.close
  end
#hier komt het complete xml bestand binnen en vervolgens worden hier te taken doorgestuurd naar andere methods  
  def parse_xml_file(data)
    doc = REXML::Document.new(data)
    root = doc.root
    print "root: #{root.text}"
    Attribute.find_by_sql("DELETE FROM attributes")
    Category.find_by_sql("DELETE FROM categories")
    ProductAttribute.find_by_sql("DELETE FROM product_attributes")
    ProductCategory.find_by_sql("DELETE FROM product_categories")
    parse_categories(root.elements["categories"])
    parse_attributes(root.elements["attributes"])
    parse_products(root.elements["products"])

    c = Category.new(:parent_id => 0)
    c.save
    c.destroy
  end
  
  private
#is de begin method voor de complete category structuur en deze roept voor de roots de parse_category aan
  def parse_categories(categories_element)
    categories_element.each_element do |element|
      parse_category(nil, element)
    end
  end
#methode om een string om te zetten naar een boolean, ik kon deze niet vinden in de ruby documentatie  
  def self.string_to_boolean(string)
    if(string == "true")
      return true
    elsif(string == "false")
      return false
    end
  end
#parsed de categorie boom
#deze methode is recursief, dus als er binnen een categorie andere categorieen zitten, dan wordt voor die elementen opnieuw deze method aangeroepen, en wordt de parent hier mee gegeven 
  def parse_category(parent, category_element)
    category = Category.new
    if(parent != nil)
      category.parent_id = parent.id
    else
      category.parent_id = 0
    end
    if(category_element.has_attributes?)
      category.name = category_element.attributes['name']
    end

    category.send(:create_without_callbacks)

    if(category_element.has_elements?)
      category_element.each_element do |element|
        parse_category(category,element)
      end
    end
  end
  
#de xml tag voor attributen bestaat uit 1 <attributes> tag en daarin staan alle attributen, in deze methode worden dan binnen die attributes tag per attribuut de parse_attribute aangeroepen.
  def parse_attributes(attributes_element)
    attributes_element.each_element do |element|
      parse_attribute(element)
    end
  end
 #hier wordt 1 attribuut omgezet naar de tabel 
  def parse_attribute(attribute_element)
    if(attribute_element.has_attributes?)
      attribute = ::Attribute.new
      attribute.name = attribute_element.attributes['name']
      attribute.save
      attribute.searchable = Parser.string_to_boolean(attribute_element.attributes['searchable'])
      attribute.filterable = Parser.string_to_boolean(attribute_element.attributes['filterable'])
      attribute.save
    end
  end
 #de xml tag voor producten bestaat uit een <products> tag en daarin staan dan alle producten beschreven, deze method roept per product de methode aan om de xml code om te zetten naar een tabel 
  def parse_products(products_element)
    products_element.each_element do |element|
      parse_product(element)
    end
  end
#hier wordt een product aangemaakt. Als het product al in de database staat, dan wordt dat product gebruikt om aan te passen.
#Dit wordt gedaan omdat anders bestellingen verwijzen naar producten die niet meer bestaan
#verder worden de attributen en categorieen in een andere methode aangemaakt 
  def parse_product(product_element)
    if(product_element.has_attributes?)
      product = Product.first(:conditions => ['name = ?',product_element.attributes['name']])
      if(product == nil)
        product = Product.new
        product.name = product_element.attributes['name']
      end
      product.price = product_element.attributes['price']
      product.stock = product_element.attributes['stock']
      product.description = product_element.attributes['description']

      unless product_element.attributes['image_src'].blank?
        product.image.upload_url( product_element.attributes['image_src'] )
      end


      product.save
      product_element.each_element('product_attribute') do |element|
        parse_product_attribute(product,element)
      end
      product_element.each_element('product_category') do |element|
        parse_product_category(product,element)
      end
    end
  end
#hier worden de attributen gekoppeld aan de producten  
  def parse_product_attribute(product,product_attribute_element)
    if(product_attribute_element.has_attributes?)
      attribute_name = product_attribute_element.attributes['name']
      attribute = ::Attribute.first(:conditions => ['name = ?',attribute_name])
      if(attribute != nil)
        product_attribute = ProductAttribute.new
        product_attribute.product_id = product.id
        product_attribute.attribute_id = attribute.id
        product_attribute.value = product_attribute_element.attributes['value']
        product_attribute.save
      end
    end
  end
#hier worden de categorieen gekoppeld aan de producten  
  def parse_product_category(product,product_category_element)
    if(product_category_element.has_attributes?)
      category_name = product_category_element.attributes['name']
      category = Category.first(:conditions => ['name = ?',category_name])
      if(category != nil)
        product_category = ProductCategory.new
        product_category.product_id = product.id
        product_category.category_id = category.id
        product_category.save
      end
    end
  end
end